<?php

/**
 * Class User_files_service 用户文件相关业务逻辑
 * @author: Calvin
 * @email : hongbinfu@163.com
 * @readme: 用户文件相关业务逻辑处理类
 */
class User_files_service extends MY_Service
{
    public function __construct()
    {
        parent::__construct();
        $this->load->language('files');
        $this->load->model('user_model');
        $this->load->model('user_files_model');
        $this->load->model("user_policies_model");
        $this->load->library('traces');
    }

    public function parse_filename_info($name)
    {
        if(empty($name))
        {
            return $this->set_error(7003);
        }
        else
        {
            $arr = explode ( ".", $name);
            $len = count ( $arr );
            $ext_name = strtolower( $arr[$len-1]);
            unset($arr[$len-1]);
            return array("name"=>implode("",$arr),"ext"=>$ext_name);
        }
    }

    /**
     * 获取文件夹和文件列表
     * @param $uid 用户id
     * @param int $folder_id 当前文件夹id
     * @param string $keyword 关键字
     * @param string $sort 排序字段
     * @param string $direction 排序类型 asc升序 desc降序
     * @param array $condition 其他条件
     */
    public function get_list($uid,$folder_id=0,$keyword="",$sort="name",$direction="asc",$condition=array("deleted"=>0),$field="",$limit=false)
    {

        $f_model = $this->user_files_model;
        $data = array("files"=>null,"folders"=>null,"total"=>0);
        //文件夹
        $folders = $f_model->get_folder_list($uid,$folder_id,$keyword,$condition,$sort,$direction,$field,$limit);
        //var_export($f_model->db->last_query());exit;
        if(!empty($folders))
        {
            $data['total'] +=(int)$folders['total'];
            $data['folders'] = $folders['rows'];
        }
        //文件
        $files = $f_model->get_file_list($uid,false,$folder_id,$keyword,$condition,$sort,$direction,$field,"",$limit);
        if(!empty($files))
        {
            $data['total'] +=(int)$files['total'];
            $data['files'] = $files['rows'];
        }
        return $data;
    }

    /**
     *
     * 获取用户的文件列表或者获取策略过期的文件列表
     * @readme 由于查询过期策略必须关联策略表，所以$find_exp_policy_files参数区分两种查询
     * @param $uid 用户id
     * @param bool $find_exp_policy_files 是否是查找默认策略过期的文件列表
     * @param int $folder_id 文件夹id
     * @param string $keyword 关键字
     * @param array $conditions 其他条件
     * @param string $sort 排序
     * @param string $direction asc升序 desc降序
     * @param string $file_fields 文件表的字段
     * @param string $ftype_fields 文件类型表的字段
     * @param string|array $limit 获取多少行 例如：0,15则从0开始取15条
     * @return array|null
     */
    public function get_file_list($uid,$find_exp_policy_files=false,$folder_id=0,$keyword="",$conditions=array("deleted"=>0),$sort="name",$direction="asc",$file_fields="",$ftype_fields="",$limit=false)
    {
        if(empty($file_fields)){
            $file_fields = "id,name,size,creation_ts,modify_ts,access_denied,ext_name";
        }
        return $this->user_files_model->get_file_list($uid,$find_exp_policy_files,$folder_id,$keyword,$conditions,$sort,$direction,$file_fields,$ftype_fields,$limit);
    }

    /**
     * 获取文件夹列表
     * @param $uid
     * @param int $folder_id
     * @param string $keyword
     * @param string $sort
     * @param string $direction
     * @param string $fields
     * @param array $condition
     * @param string|array $limit
     * @return array|null
     */
    public function get_folder_list($uid,$folder_id=0,$keyword="",$sort="name",$direction="asc",$fields="",$condition=array("deleted"=>0),$limit=false)
    {
        if(empty($fields)){
            $fields = "id,name,creation_ts,modify_ts,access_denied";
        }
        //文件夹
        return $this->user_files_model->get_folder_list($uid,$folder_id,$keyword,$condition,$sort,$direction,$fields,$limit);
    }

    /**
     * 已经下载过授权副本的文件列表
     * @param $uid
     * @param int $folder_id
     * @param string $keyword
     * @param string $sort
     * @param string $direction
     * @param array $condition 其他条件
     * @param array|string $fields 获取的字段
     */
    public function get_downloaded_file_list($uid,$folder_id=0,$keyword="",$sort="name",$direction="asc",$condition=array("deleted"=>0),$fields="id,name,size,creation_ts,modify_ts,access_denied,ext_name",$limit=false)
    {
        $f_model = $this->user_files_model;
        $condition = array_merge($condition,array("downloaded"=>1));
        $files = $f_model->get_file_list($uid,false,$folder_id,$keyword,$condition,$sort,$direction,$fields,"",$limit);
        if(!empty($files))
        {
            $data=$files;
        }
        else
        {
            $data = array("rows"=>null,"total"=>0);
        }
        return $data;
    }

    /**
     * 策略过期的文件列表
     * @param $uid
     * @param int $folder_id
     * @param string $keyword
     * @param string $sort
     * @param string $direction
     * @param array $condition
     */
    public function get_exp_file_list($uid,$folder_id=0,$keyword="",$sort="name",$direction="asc",$condition=array("deleted"=>0),$fields="id,name,size,creation_ts,modify_ts,access_denied,ext_name",$limit=false)
    {
        $f_model = $this->user_files_model;
        $files = $f_model->get_file_list($uid,true,$folder_id,$keyword,$condition,$sort,$direction,$fields,"",$limit);
        if(!empty($files))
        {
            $data=$files;
        }
        else
        {
            $data = array("rows"=>null,"total"=>0);
        }
        return $data;
    }

    /**
     * 已经分享的文件列表
     * @param $uid
     * @param int $folder_id
     * @param string $keyword
     * @param string $sort
     * @param string $direction
     * @param array $condition 其他条件
     * @param array|string $fields 获取的字段
     */
    public function get_share_file_list($uid,$folder_id=0,$keyword="",$sort="name",$direction="asc",$condition=array("deleted"=>0),$fields="id,name,size,creation_ts,modify_ts,access_denied,ext_name",$limit=false)
    {
        $f_model = $this->user_files_model;
        $condition = array_merge($condition,array("shared"=>1));
        $files = $f_model->get_file_list($uid,false,$folder_id,$keyword,$condition,$sort,$direction,$fields,"",$limit);
        if(!empty($files))
        {
            $data=$files;
        }
        else
        {
            $data = array("rows"=>null,"total"=>0);
        }
        return $data;
    }

    public function get_safe_name($name,$list)
    {
        $num = $this->get_safe_name_num($name,$list);
        return $num==0?$name:$name."(".$num.")";
    }

    /**
     * 返回新建文件的名称
     * @param $name 文件名
     * @param $list 列表
     * @param $ext 扩展名
     * @return string
     */
    public function get_safe_extname($name, $list, $ext) {
        $num = $this->__safe_extname($name, $list, $ext);
        return empty($num)? $name : $name."(".$num.")";
    }

    public function get_safe_name_num($name,$list)
    {
        if(empty($list))
        {
            return 0;
        }
        $num=array();
        //遍历和解析文件夹名称
        foreach($list as $item)
        {
            //preg_match("/^".preg_quote($name)."$/", $item, $match);
            //if(!empty($match) && !in_array(0,$num))
            if($name == $item)
            {
                $num[]=0;
            }
            else
            {
                preg_match("/^".preg_quote($name)."\(([1-9]+[0-9]*)\)$/", $item, $match1);
                if(!empty($match1) && !in_array((int)$match1[1],$num))
                {
                    $num[]=(int)$match1[1];
                }
            }
        }
        if(empty($num))
        {
            return 0;
        }
        else
        {
            sort($num);
            //如果找不到新建文件夹则max=0
            if($num[0]!=0)
            {
                return 0;
            }
            $max = 0;
            //取出中间断开的部分 比如新建文件夹(2)与新建文件夹(5),则max=3
            foreach($num as $k => $v)
            {
                $max = $v+1;
                if(isset($num[$k+1]) && $num[$k+1]!=($v+1))
                {
                    break;
                }
            }
            return $max;
        }
    }


    /**
     * 获取新建文件夹可以的数值 如新建文件夹(可用数值)
     * @param $folder_list 文件夹列表
     * @return int
     */
    public function get_new_folder_num($folder_list)
    {
        if(empty($folder_list))
        {
            return 0;
        }
        $num=array();
        //遍历和解析文件夹名称
        foreach($folder_list as $name)
        {
            $new_folder_name = $this->lang->line("new_folder");
            //preg_match("/^".$new_folder_name."$/", $name, $match);
            //if(!empty($match) && !in_array(0,$num))
            if($new_folder_name==$name)
            {
                $num[]=0;
            }
            else
            {
                preg_match("/^".$new_folder_name."*\(([1-9]+[0-9]*)\)$/", $name, $match1);
                if(!empty($match1) && !in_array((int)$match1[1],$num))
                {
                    $num[]=(int)$match1[1];
                }
            }
        }
        if(empty($num))
        {
            return 0;
        }
        else
        {
            sort($num);
            //如果找不到新建文件夹则max=0
            if($num[0]!=0)
            {
                return 0;
            }
            $max = 0;
            //取出中间断开的部分 比如新建文件夹(2)与新建文件夹(5),则max=3
            foreach($num as $k => $v)
            {
                $max = $v+1;
                if(isset($num[$k+1]) && $num[$k+1]!=($v+1))
                {
                    break;
                }
            }
            return $max;
        }
    }


    /**
     * 获取文件或者文件夹具体信息
     * @param $uid
     * @param $ftype
     * @param $fid
     * @return null
     */
    public function get_detail($uid,$ftype,$fid)
    {
        if(empty($uid) || !is_numeric($ftype) || empty($fid))
        {
            return $this->set_error(1003);
        }
        if($ftype==0)
        {
            $info = $this->user_files_model->get_file_info($uid,$fid,true);
            if(empty($info))
            {
                return $this->set_error(7001);
            }
            else
            {
                return $info;
            }
        }
        else if($ftype==1)
        {
            $info =  $this->user_files_model->get_folder_info($uid,$fid);
            if(empty($info))
            {
                return $this->set_error(7100);
            }
            else
            {
                return $info;
            }
        }
        else
        {
            return null;
        }
    }

    public function get_path_info($uid,$fid)
    {
        $info =  $this->user_files_model->get_folder_path_info($uid,$fid);
        if(empty($info))
        {
            return $this->set_error(7100);
        }
        else
        {
            return $info;
        }
    }

    public function get_file_data($owner,$fids,$file_field="", $folder_field="") {
        if (empty($owner) || empty($fids))
            return $this->set_error(1003);

        return $this->user_files_model->get_file_data($owner,$fids,$file_field, $folder_field);
    }

    /**
     * 获取文件夹的路径信息
     * @param $uid
     * @param $fids 文件夹组
     * @param $i_field 字段
     * @return mixed
     */
    public function get_folders_path($uid,$i_fids,$i_field="") {
        if (empty($uid) || empty($i_fids))
            return $this->set_error(1003);

        return $this->user_files_model->get_folders_path($uid,$i_fids,$i_field);
    }

    public function get_folder_path($i_fids,$folder_field="*") {
        if (empty($i_fids))
            return $this->set_error(1003);

        return $this->user_files_model->get_folder_path($i_fids,$folder_field);
    }

    /**
     * 获取源文件信息
     */
    public function get_file_resource($fid)
    {
        if(empty($fid))
        {
            return $this->set_error(1003);
        }
        $data =  $this->user_files_model->get_all_file_info($fid,null,null,null,"source_guid","","");
        if(!empty($data) && isset($data['source_guid']))
        {
            return $data['source_guid'];
        }
        else
        {
            return "";
        }
    }

    /**
     *
     * 获取某个文件夹的文件个数
     * @param $uid
     * @param int $folder_id
     * @return int
     */
    public function get_folder_file_count($uid,$folder_id=0)
    {
        if(empty($uid))
        {
            return $this->set_error(1003);
        }
        return $this->user_files_model->get_folder_file_count($uid,$folder_id);

    }

    /**
     * 检查文件是否已经上传
     * @param $md5
     * @param $fields
     * return mixed
     */
    public function check_source_file_exists($md5,$fields="guid")
    {
        return $this->user_files_model->check_source_file_exists($md5,$fields);
    }

    public function can_add_file_simple($uid,$size)
    {
        if(empty($uid) || !is_numeric($size))
        {
            return $this->set_error(1003);
        }
        /*$file_type = $this->user_files_model->mime_type_info($mime_type);
        if(empty($file_type))
        {
            //文件类型不支持
            return $this->set_error(7002);
        }*/
        //检查空间是否足够
        $space = $this->user_model->get_user_info(array("id"=>$uid),"capacity,used_space");
        if(empty($space))
        {
            return $this->set_error(1003);
        }

        if($space['used_space']+$size>$space['capacity'])
        {
            return $this->set_error(7004);
        }

        return TRUE;

    }

    /**
     * 是否可以上传（添加）文件
     * @param $uid
     * @param $filename
     * @param $size
     * @param $mime_type
     * @return array|bool
     */
    public function can_add_file($uid,$filename,$size,$mime_type)
    {
        if(empty($uid) || empty($filename) || !is_numeric($size))
        {
            return $this->set_error(1003);
        }
        //检查文件大小
        if($size<=0)
        {
            return $this->set_error(7005);
        }
        $filename_info = $this->parse_filename_info($filename);
        if($filename_info===false)
        {
            return false;
        }
        $name = $filename_info['name'];
        //检查文件类型
        $file_type = $this->user_files_model->get_file_type($filename_info['ext']);
        if(empty($file_type))
        {
            //文件类型不支持
            return $this->set_error(7002);
        }
        //后缀名与文件类型匹配检查
        if($this->config->item("check_upload_mime_type") && $file_type['mime_type'] != $mime_type)
        {
            return $this->set_error(7006);
        }
        //检查空间是否足够
        $space = $this->user_model->get_user_info(array("id"=>$uid),"capacity,used_space");
        if(empty($space))
        {
            return $this->set_error(1003);
        }

        if($space['used_space']+$size>$space['capacity'])
        {
            return $this->set_error(7004);
        }

        return array("name"=>$name,"mime_type"=>$file_type['mime_type'],"type_id"=>$file_type['id'],"ext_name"=>$filename_info['ext']);
    }

    /**
     * 添加文件
     * @param $uid 用户id
     * @param $filename 文件名
     * @param $size 文件大小
     * @param $mime_type 文件mime类型
     * @param $md5 文件md5值
     * @param $source_guid 源文件GUID
     * @param int $folder_id  所属文件夹id
     * @param string $file_guid  文件的全局guid
     * @return array
     */
    public function add_file($uid,$filename,$size,$mime_type,$md5,$source_guid,$folder_id=0,$file_guid="")
    {
        //简单检查参数
        if(empty($uid) || empty($filename) || !is_numeric($size) || empty($mime_type) || empty($source_guid))
        {
            return $this->set_error(1003);
        }
        /*if($size<=0)
        {
            return $this->set_error(7005);
        }
        //解析文件名 array("name"=>"","ext"=>"")
        $filename_info = $this->parse_filename_info($filename);
        if($filename_info===false)
        {
            return false;
        }
        $name = $filename_info['name'];
        //检查文件类型
        $file_type = $this->user_files_model->get_file_type($filename_info['ext']);
        if(empty($file_type))
        {
            //文件类型不支持
            return $this->set_error(7002);
        }
        //后缀名与文件类型匹配检查
        if($file_type['mime_type'] != $mime_type)
        {
            return $this->set_error(7006);
        }
        //检查空间是否足够
        $space = $this->user_model->get_user_info(array("id"=>$uid),"capacity,used_space");
        if(empty($space))
        {
            return $this->set_error(1003);
        }

        if($space['used_space']+$size>$space['capacity'])
        {
            return $this->set_error(7004);
        }*/
        $check = $this->can_add_file($uid,$filename,$size,$mime_type);
        if($check===FALSE)
        {
            return FALSE;
        }

        $name = $check['name'];
        /*//检查源文件是否已经存在
        $source = $this->check_source_file_exists($md5);
        if($source)
        {
            $source_guid = $source['guid'];
        }
        //不存在则新建源文件信息
        else
        {
            $add_source = $this->add_source_file($source_guid,$md5);
            if($add_source===false)
            {
                return $this->set_error(1002);
            }
        }*/

        if(empty($file_guid))
        {
            $file_guid = Common::uniqid();
        }
        $folder_info = array();
        if($folder_id>0)
        {
            $folder_info = $this->user_files_model->get_folder_info($uid,$folder_id,true,array("deleted"=>0),array(),"id,name,access_denied,path,pid,level","data,is_global,expiration_ts,expired");
            if(empty($folder_info))
            {
                return $this->set_error(7100);
            }
        }
        $time = time();

        $brother=$this->user_files_model->get_folder_files($uid,$folder_id,FALSE,"name, ext_name");
        if(!empty($brother))
        {
            //$name = $this->get_safe_extname($name, Common::array_column($brother,"name"));
            $file_names = $this->__file_list_name($brother, "name,ext_name");
            $name = $this->get_safe_extname($name,$file_names, $check['ext_name']);
        }
        $file_data=array(
            "guid"=>$file_guid,
            "name"=>$name,
            "size"=>$size,
            "type"=>$check['type_id'],
            "ext_name"=>$check['ext_name'],
            "creation_ts"=>$time,
            "modify_ts"=>$time,
            "folder_id"=>$folder_id,
            "source_guid"=>$source_guid,
            "shared"=>0,
            "access_denied"=>!empty($folder_info)?$folder_info["access_denied"]:0
        );
        $add = $this->user_files_model->add_file($uid,$file_data);
        if($add===false)
        {
            return $this->set_error(1002);
        }
        else
        {
            $file_data['id'] = $this->user_files_model->get_insert_id();
            $file_data['ext_name'] = $check['ext_name'];
        }
        //标记用户的使用空间
        $this->user_model->update_offset($uid,"used_space",$size);

        //复制文件夹的策略
        if(!empty($folder_info) && !empty($folder_info["data"]))
        {
            $policy=array(
                "ftype"=>1,//文件
                "fid"=>$file_data['id'],
                "data"=>$folder_info["data"],
                "is_global"=>$folder_info["is_global"],
                "creation_ts"=>time(),
                "modify_ts"=>time(),
                "expiration_ts"=>$folder_info['expiration_ts'],
                "expired"=>$folder_info['expired']
            );
            $policy_data = json_decode($folder_info["data"],true);
        }
        //默认加策略，只可查看一次
        else
        {
            #value_set可查阅次数,value已查阅次数
            $policy_data = array(array('des' => 'open_counter', 'value_set' => 1, 'value' => 0));
            $init_policy = $this->config->item('init_policy');
            if (! empty($init_policy))
                $policy_data = $init_policy;

            $policy=array(
                "ftype"=>1,//文件
                "fid"=>$file_data['id'],
                "data"=>json_encode($policy_data),
                "is_global"=>1,
                "creation_ts"=>time(),
                "modify_ts"=>time(),
                "expiration_ts"=>0,
                "expired"=>0
            );
        }
        $add_policy = $this->user_policies_model->add_policy($uid,$policy);
        if($add_policy===false)
        {
            return $this->set_error(1002);
        }
        $policy_traces = array();
        foreach($policy_data as $item)
        {
            if(!empty($item['value_set'])) {
                $policy_traces[] = array(
                    "file_id" => $file_data['id'],
                    "event" => Traces::get_policy_event($item['des']),
                    "actor" => $uid,
                    "end" => $item['value_set']
                );
            }
        }
        //文件轨迹
        Traces::trace_file($file_data['id'],Traces::EVENT_UPLOAD_FILE,"","",$uid);
        //记录策略的文件轨迹
        if(!empty($policy_traces))
        {
            Traces::trace_file($policy_traces,Traces::EVENT_SET_POLICY);
        }
        return $file_data;
    }

    /**
     * 添加源文件
     * @param $guid
     * @param $md5
     * @return array
     */
    public function add_source_file($guid,$md5)
    {
        if(empty($guid) || empty($md5))
        {
            return $this->set_error(1002);
        }
        $data=array(
            "md5"=>$md5,
            "hash"=>Common::time33($md5),
            "guid"=>$guid,
            "creation_ts"=>time()
        );
        $add = $this->user_files_model->add_source_file($data);
        if($add===false)
        {
            return $this->set_error(1002);
        }
        else
        {
            $data['id'] = $this->user_files_model->get_insert_id();
            return $data;
        }
    }

    /**
     *
     * 添加受控文件
     * @param $fid 用户文件id
     * @param $size 文件大小
     * @param $type 受控文件类型 1:exe 2:简单加解密
     * @param $guid 受控文件的GUID
     * @param $cipher 受控文件的秘钥
     * @param $md5 受控文件的md5值
     * @return array
     */
    public function add_secure_file($fid,$size,$type,$guid,$cipher,$md5="")
    {
        if(empty($fid) || empty($size) || empty($type) || empty($guid) || empty($cipher))
        {
            return $this->set_error(1003);
        }
        $data=array(
            "fid"=>$fid,
            "md5"=>$md5,
            "md5_hash"=>Common::time33($md5),
            "size"=>$size,
            "type"=>$type,
            "guid"=>$guid,
            "cipher"=>$cipher,
            "creation_ts"=>time()
        );
        $add = $this->user_files_model->add_secure_file($data);
        if($add===false)
        {
            return $this->set_error(1002);
        }
        else
        {
            $data['id'] = $this->user_files_model->get_insert_id();
            return $data;
        }
    }



    /**
     *
     * 更新文件或文件夹的描述
     * @param $uid 用户id
     * @param $type 文件夹或者文件 0文件 1文件夹
     * @param $fid
     * @param string $description
     */
    public function update_description($uid,$fid,$type=0,$description="")
    {
        if(empty($uid) || empty($fid))
        {
            return $this->set_error(1003);
        }
        $data=array(
            "description"=>$description,
            "modify_ts"=>time()
        );
        $where=array(
            "id"=>$fid
        );
        if($type==1)
        {
            return $this->user_files_model->update_folder($uid,$where,$data);
        }
        else
        {
            return $this->user_files_model->update_file($uid,$where,$data);
        }
    }

    /**
     * 更新文件是否及时收回
     * @param $uid
     * @param array $files 文件列表
     * @param array $folders 文件夹列表
     * @param int $denied
     * @param bool $all 是否应用于子目录
     * @return bool
     */
    public function update_access_denied($uid,$files=array(),$folders=array(),$denied=0,$all=false)
    {
        if(empty($uid) || (empty($files) && empty($folders)))
        {
            return $this->set_error(1003);
        }
        //文件轨迹
        $traces = array();
        //更新文件
        if(!empty($files))
        {
            $edit = $this->user_files_model->update_file_by_ids($uid,$files,array("access_denied"=>$denied));
            if($edit===false)
            {
                return $this->set_error(1002);
            }
            if ($this->db->affected_rows() < 1)
            {
                return $this->set_error(1003);
            }

            foreach($files as $k=>$v)
            {
                $traces[]=array(
                    "file_id"=>$v,
                    "actor" => $uid,
                    "event" => $denied==0?Traces::EVENT_ENABLE_SECURE_FILE:Traces::EVENT_DISABLE_SECURE_FILE
                );
            }
        }

        //更新文件夹，会应用目录下的文件以及子子目录的文件及文件夹
        if(!empty($folders))
        {
            //file_put_contents("debug.txt",json_encode(array($uid,$folders,$denied,$all)));
            $edit2 = $this->user_files_model->update_folder_access_denied($uid,$folders,$denied,$all);
            if($edit2===false)
            {
                return $this->set_error(1002);
            }
            $f_ids = $this->user_files_model->get_folder_files($uid,$folders,$all,"id");
            foreach($f_ids as $f)
            {
                $traces[]=array(
                    "file_id"=>$f['id'],
                    "actor" => $uid,
                    "event" => $denied==0?Traces::EVENT_ENABLE_SECURE_FILE:Traces::EVENT_DISABLE_SECURE_FILE
                );
            }
        }
        if(!empty($traces))
        {
            Traces::trace_file($traces,0);
        }
        return true;
    }

    /**
     * 添加文件夹
     * @param $uid 用户id
     * @param $name 文件夹的名字
     * @param int $pid 父级文件夹的id
     * @return array
     */
    public function add_folder($uid,$name,$pid=0)
    {
        if(empty($uid) || ('' === $name))
        {
            return $this->set_error(1003);
        }
        //检查同级文件夹名称是否存在
        $check =$this->user_files_model->check_folder_exists($uid,array("pid"=>$pid,"name"=>$name,"deleted"=>0));
        if($check)
        {
            return $this->set_error(7101);
        }
        $parent_info = array();
        if($pid>0)
        {
            $parent_info = $this->user_files_model->get_folder_info($uid,$pid,true,array("deleted"=>0),array(),"id,name,access_denied,path,pid,level","data,is_global,expiration_ts,expired");
            if(empty($parent_info))
            {
                return $this->set_error(7102);
            }
        }
        if(empty($parent_info))
        {
            $data=array(
                "name"=>$name,
                "level"=>1,
                "pid"=>$pid,
                "path"=>"0",
                "creation_ts"=>time(),
                "modify_ts"=>time(),
                "access_denied"=>0
            );
        }
        else
        {
            $data=array(
                "name"=>$name,
                "pid"=>$pid,
                "path"=>$parent_info['path'].",".$pid,
                "level"=>(int)$parent_info['level']+1,
                "access_denied"=> (int)$parent_info['access_denied'],
                "creation_ts"=>time(),
                "modify_ts"=>time()
            );
        }

        $add = $this->user_files_model->add_folder($uid,$data);
        if($add === false)
        {
            return $this->set_error(1002);
        }
        else
        {
            $fid =$this->user_files_model->get_insert_id();
            if(!empty($parent_info) && !empty($parent_info["data"]))
            {
                $policy=array(
                    "ftype"=>2,
                    "fid"=>$fid,
                    "data"=>$parent_info["data"],
                    "is_global"=>$parent_info["is_global"],
                    "creation_ts"=>time(),
                    "modify_ts"=>time(),
                    "expiration_ts"=>$parent_info['expiration_ts'],
                    "expired"=>$parent_info['expired'],

                );
                $this->user_policies_model->add_policy($uid,$policy);
            }
            $data['id']=$fid;
            return $data;
        }

    }

    /**
     * 获取多个文件夹信息
     * @param $owner
     * @param $ids
     * @param string $where
     * @param string $field
     * @return mixed
     */
    public function  get_multidim_folders($owner,$ids,$where="",$field="") {
        if (empty($owner) || empty($ids))
            return $this->set_error(1003);

        return $this->user_files_model-> get_multidim_folders($owner,$ids,$where,$field);
    }

    /**
     * 更新文件夹名称
     * @param $uid
     * @param $folder_id
     * @param $name 文件夹名称(同级不能重复)
     */
    public function update_folder_name($uid,$folder_id,$name)
    {
        if(empty($uid) || empty($folder_id) || empty($name))
        {
            return $this->set_error(1003);
        }

        //检查文件夹是否存在
        $find =$this->user_files_model->get_folder_info($uid,$folder_id,false,array(),array(),"id,name,pid");
        if(empty($find))
        {
           return $this->set_error(7100);
        }
        //检查同级文件夹名称是否已经存在
        $check =$this->user_files_model->check_folder_exists($uid,array("pid"=>$find['pid'],"name"=>$name,'id<>'=>$folder_id,"deleted"=>0));
        //file_put_contents("debug.txt",$this->db->last_query());
        if($check)
        {
            return $this->set_error(7101);
        }
        $edit = $this->user_files_model->update_folder($uid,array("id"=>$folder_id),array("name"=>$name,"modify_ts"=>time()));
        if($edit===false)
        {
            return $this->set_error(1002);
        }
        else
        {
            return true;
        }
    }



    /**
     * 移动文件或文件夹位置
     * @param $uid 用户id
     * @param array $files 文件id
     * @param array $folders 文件夹id
     * @param int $to 移动的文件id
     * @return bool
     */
    public function move($uid,$files=array(),$folders=array(),$to=0)
    {
        
        if(empty($files) && empty($folders))
        {
            return $this->set_error(1003);
        }
        //检查目标文件夹是否存在
        $check = $to==0?true:$this->user_files_model->check_folder_exists($uid,array("id"=>$to),"id");
        if(!$check)
        {
            return $this->set_error(7100);
        }
        if(!empty($files))
        {
            //所选的文件列表信息
            $files_info = $this->user_files_model->get_files_info($uid,$files,FALSE,array(),array(),"id,folder_id,name,ext_name","");
            if(empty($files_info))
            {
                return $this->set_error(1003);
            }

            //防止移动文件后重名
            //文件夹下的文件信息
            $brother=$this->user_files_model->get_folder_files($uid,$to,FALSE,"name,ext_name");
            if(!empty($brother))
            {
                $in = array();
                //$brother = Common::array_column($brother,"name");
                $brother = $this->__file_list_name($brother, "name,ext_name");  //目标文件夹下的文件列表
                //$files_name = Common::array_column($files_info,"name");
                //$files_name = $this->__file_list_name($files_info, "name,ext_name");  //选择的文件列表
                foreach($files_info as $v) {
                    //当前文件存在文件夹中, 将文件id从$files清除
                    if ($v['folder_id'] == $to) {
                        $file_idx = array_search($v['id'], $files);
                        if ($file_idx !== false){
                            unset($files[$file_idx]);
                            //跳过重命名
                            continue;
                        }
                    }

                    //文件全名
                    $full_name = $v['name'].'.'.$v['ext_name'];

                    //如果已存在文件名
                    if (in_array($full_name, $brother)) {
                        //更新名字
                        $name = $this->get_safe_extname($v['name'], $brother, $v['ext_name']);
                        $back_name = $name.'.'.$v['ext_name'];
                        $brother[] = $back_name;
                        //$name = $this->get_safe_name($name, $files_name);

                        $in[] = array("id"=>$v['id'],"name"=>$name,"modify_ts"=>time());
                    }
                }

                if(!empty($in))
                {
                    $edit = $this->user_files_model->update_files($in);
                    if($edit===FALSE)
                    {
                        return $this->set_error(1002);
                    }
                }
                //Common::console($name."->".$check['name']);
                /*if($name!=$check['name'])
                {
                    $edit = $this->user_files_model->update_folder($uid,array("id"=>$check['id']),array("name"=>$name,"modify_ts"=>time()));
                    if($edit===FALSE)
                    {
                        return $this->set_error(1002);
                    }
                }*/
            }

            //如果上一步过滤掉同目录下的文件后还有文件
            if (! empty($files)) {
                $this->user_files_model->move_files($uid,$files,$to);
            }

            //从分享列表中删除
            $this->load->model("share_page_model");
            $delete_file_sharelist = $this->share_page_model->delete_sharelist_file($uid, $files, 1);
            #删除文件后，清空code为空的分享码
            if ($delete_file_sharelist) {
                $this->share_page_model->clear_sharecode();
            }
        }

        //移动文件
        if(!empty($folders))
        {

        }

        return true;
    }

    /**
     * 删除文件或者文件夹
     * @param $uid 用户id
     * @param string|array $files 文件列表 1 | array(1,2,3)
     * @param string|array $folders 文件夹列表 1 | array(1,2,3)
     * @param bool $real
     * @return bool
     */
    public function delete($uid,$files=array(),$folders=array(),$real=true)
    {
        if(empty($files) && empty($folders))
        {
            return $this->set_error(1003);
        }
        $used=0;
        //删除文件
        if(!empty($files))
        {
            $files_size = $this->user_files_model->get_files_size($uid,$files);
            $df = $this->user_files_model->delete_files($uid,$files,$real);
            if($df)
            {
                $used +=$files_size;
            }
        }
        //删除文件夹已经所以子目录的文件夹
        if(!empty($folders))
        {
            $folders_size = $this->user_files_model->get_folders_size($uid,$folders);
            $dfd = $this->user_files_model->delete_folders($uid,$folders,$real);
            if($dfd)
            {
                $used +=$folders_size;
            }
        }
        //释放空间
        if($used>0)
        {
            $this->user_model->update_offset($uid,"used_space",-$used);
        }

        return true;
    }

    /**
     *
     * 获取文件信息（不检测用户）
     * @param $fid 文件id
     * @param array $file_conditions 文件表的条件
     * @param array $policy_conditions 策略表的条件
     * @param array $secure_conditions 受控文件的条件
     * @param string $file_fields 文件表的字段
     * @param string $policy_fields 策略表的字段
     * @param string $secure_fields 受控文件表的字段
     * @return null
     */
    public function get_all_file_info($fid,$file_conditions=array(),$policy_conditions=array(),$secure_conditions=array(),$file_fields="id,name,size,creation_ts,modify_ts,access_denied,description",$policy_fields="data",$secure_fields="")
    {
        return $this->user_files_model->get_all_file_info($fid,$file_conditions,$policy_conditions,$secure_conditions,$file_fields,$policy_fields,$secure_fields);
    }
    /**
     *
     * 获取文件信息（不检测用户）
     * @param $fid 文件id
     * @param array $file_conditions 文件表的条件
     * @param array $policy_conditions 策略表的条件
     * @param array $secure_conditions 受控文件的条件
     * @param string $file_fields 文件表的字段
     * @param string $policy_fields 策略表的字段
     * @param string $secure_fields 受控文件表的字段
     * @return null
     */
    public function get_all_file_info_by_guid($guid,$file_conditions=array(),$policy_conditions=array(),$secure_conditions=array(),$file_fields="id,name,size,creation_ts,modify_ts,access_denied,description",$policy_fields="data",$secure_fields="")
    {
        return $this->user_files_model->get_all_file_info_by_guid($guid,$file_conditions,$policy_conditions,$secure_conditions,$file_fields,$policy_fields,$secure_fields);
    }


    public function update_file_info($where,$data)
    {
        return $this->user_files_model->open_update_file($where,$data);
    }

    /**
     * 获取子目录\子孙目录的文件
     * @param $owner  拥有者
     * @param $ids  编号列表
     * @param $type  类型：1.文件, 2.文件夹
     * @param bool|TRUE $all  是否查找子孙目录
     * @param string $file_field  u_files表中的字段
     * @param string $folder_field  u_folders表的字段
     * @param string $secure_field  secure_files表中的guid,供下载使用
     * @return bool
     */
    public function get_children_path($owner, $ids, $type, $all=TRUE, $file_field="id,access_denied", $folder_field="", $secure_field="", $file_type=2) {
        if (empty($owner) || empty($ids) || empty($type))
            return $this->set_error(1003);

        if (empty($file_type)) $file_type = 2;

        if ($type == 1) {
            return $this->user_files_model->get_folder_files_path($owner, $ids, $all, $file_field, $folder_field, $secure_field, $file_type);
        } else {
            return $this->user_files_model->get_folder_children($owner, $ids, $all, $file_field, $folder_field);
        }
    }

    public function download_source($uid="", $id="") {
        if (empty($id) || empty($uid))
            return $this->set_error(1003);

        $where = array('uid' => $uid);
        $data = $this->get_all_file_info($id, $where, null, null, "name,source_guid,ext_name", null);
        if (empty($data))
            return $this->set_error(7001);

        $name = $data['name'].".".$data['ext_name'];
        $guid = $data['source_guid'];

        $link_id = Common::download_link($guid, "download_source".$id);

        $download_exp = $this->config->item("download_expire_time");

        if (empty($link_id))
            return $this->set_error(7001);

        $data = json_encode(array("guid"=>$guid,"name"=>rawurlencode($name)));

        $redis = new Redis();
        $connect = $redis->connect($this->config->item("host", "redis"), $this->config->item("port", "redis"), $this->config->item("timeout", "redis"));
        if (!$connect)
            return $this->set_error(1019);
        $set = $redis->setex($link_id, $download_exp, $data);

        if (!$set)
            return $this->set_error(1019);

        Traces::trace_file($id, Traces::EVENT_DOWNLOAD_SOURCE_FILE, "", "", $uid);
        return $link_id;
    }

    private function __file_list_name($lists, $field) {
        if (! is_array($field))
            $field = explode(',', $field);

        $res = array();
        foreach ($lists as $key => $val) {
            $file_name = '';
            foreach ($field as $k => $v) {
                if (isset($val[$v])) {
                    if (empty($file_name)) {
                        $file_name = $val[$v];
                    } else {
                        $file_name .= '.' . $val[$v];
                    }
                }
            }
            $res[] = $file_name;
        }

        return $res;
    }

    /**
     * 返回新文件的编号
     * @param $name
     * @param $list
     * @param $ext
     * @return int|mixed
     */
    private function __safe_extname($name, $list, $ext) {
        if (empty($list))
            return 0;

        $num = array();
        $full_name = $name.'.'.$ext;
        //遍历文件列表名
        foreach ($list as $item) {
            //文件名已存在,重置
            if ($full_name == $item) {
                $num[] = 0;
            } else {
                //取值
                $preg = "/^".preg_quote($name)."\(([1-9]+[0-9]*)\)\.".preg_quote($ext)."$/";  //全名匹配
                preg_match($preg, $item, $match1);

                //判断数字是否已存在
                if (!empty($match1) && !in_array((int)$match1[1], $num)) {
                    $num[] = (int)$match1[1];
                }
            }
        }

        //不存在相同文件
        if (empty($num))
            return 0;

        sort($num);

        //如果找不到新建文件则max=0
        if ($num[0] != 0)
            return 0;

        $max = 0;
        //取出中间断开的部分 比如新建文件(2)与新建文件(5),则max=3
        foreach($num as $k => $v)
        {
            $max = $v+1;
            if(isset($num[$k+1]) && $num[$k+1]!=($v+1))
            {
                break;
            }
        }
        return $max;
    }

    /**
     * 检测文件的权限
     * @param $uid 用户的id
     * @param array $files 文件id组
     * @param array $folders 文件夹id组
     * return array('files'=>[], 'folders' => [])
     */
    public function check_own_files($uid, $files=array(), $folders=array())  {
        if (empty($uid) || (empty($files) && empty($folders))) {
            return $this->set_error(1003);
        }

        return $this->user_files_model->check_own_files($uid, $files, $folders);
    }

    /**
     * @param $uid
     * @param $keyword
     * @param $page
     * @param $total
     * @param string $field
     * @return mixed
     */
    public function search($uid, $keyword, $page=0, $total=0, $field='*') {
        if (empty($uid) || $keyword === '') {
            return $this->set_error(1003);
        }

        if (is_array($field)) {
            $field = implode(',', $field);
        }

        return $this->user_files_model->search($uid, $keyword, $page, $total, $field);
    }
}
